/*
 * @(#)DaapListener.java
 * 
 * Copyright(C) 2004 Yujin Kim
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.netexplode.jtunes.protocol.jmdns;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cdavies.itunes.Database;
import org.cdavies.itunes.ItunesConnection;
import org.cdavies.itunes.ItunesConnectionFactory;
import org.cdavies.itunes.ItunesHost;
import org.cdavies.itunes.request.NoServerPermissionException;

import com.netexplode.jtunes.Constants;
import com.netexplode.jtunes.client.player.jTunes;
import com.netexplode.jtunes.model.media.CollectionManager;
import com.netexplode.jtunes.model.media.SharedCollection;

/**
 * <code>DaapListener</code> represents .....
 * 
 * @author ykim
 * @version $Revision: 1.4 $
 * @since 0.1
 */
public class DaapListener implements ServiceListener {

    private static final Log log = LogFactory.getLog(DaapListener.class);

    private final static Hashtable servers = new Hashtable();

    /*
     * (non-Javadoc)
     * 
     * @see javax.jmdns.ServiceListener#serviceAdded(javax.jmdns.ServiceEvent)
     */
    public void serviceAdded(ServiceEvent event) {
        log.info(event.getName());

        log.info("service added : " + event);
        JmDNS jmdns = event.getDNS();
        log.info(jmdns.getHostName());
        jmdns.requestServiceInfo(Constants.DAAP_SERVICE, event.getName());
    }

    /*
     * (non-Javadoc)
     * 
     * @see javax.jmdns.ServiceListener#serviceRemoved(javax.jmdns.ServiceEvent)
     */
    public void serviceRemoved(ServiceEvent event) {
        log.info(event.getName());
        try {
            servers.remove(event.getDNS().getInterface().getHostAddress());
        }
        catch (Exception e) {
            log.info(e, e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see javax.jmdns.ServiceListener#serviceResolved(javax.jmdns.ServiceEvent)
     */
    public void serviceResolved(ServiceEvent event) {
        log.info(event.getName());
        JmDNS jmdns = event.getDNS();
        log.info(jmdns.getHostName());
        log.info("create host");

        ItunesHost host = new ItunesHost(
                jmdns.getHostName(),
                event.getName(),
                ItunesHost.ITUNES_45);

        log.info("attempt connecting to "
                + host
                + ", "
                + host.getName()
                + "| version "
                + host.getVersion());
        ItunesConnection conn = null;
        try {
            conn = getItunesConnection(jmdns, event);
            if (null == conn) {
                log.info("null connection");
                return;
            }
            log.info("connecting");
            conn.connect();

            log.info("about to create collectoin");
            if (conn.isConnected()) {
                log.info("connection successful");
                Database[] dbs = conn.getDatabases();
                List list = new ArrayList();
                for (int i = 0; i < dbs.length; i++) {
                    log.info("database = " + dbs[i].getName());
                    final SharedCollection col = (SharedCollection) CollectionManager
                            .getInstance()
                            .newInstance();
                    col.setId("" + dbs[i].getId());
                    col.setName(dbs[i].getName());
                    col.setDatabase(dbs[i]);
                    col.setConnection(conn);
                    col.setItunesHost(host);
                    col.setTracks(conn.getTracklist(dbs[i].getId()));

                    log.info("adding "
                            + dbs[i].getName()
                            + " with "
                            + dbs[i].getTrackCount()
                            + " | "
                            + conn.getTracklist(dbs[i].getId()).length);

                    list.add(col);
                }

                CollectionManager.getInstance().setSharedCollections(list);

                servers.put(jmdns.getInterface().getHostAddress(), host);
                log.info("refreshing panel");
                jTunes.refreshSharedCollectionPanel();

                log.info("registerd " + host.getName());
            }
        }
        catch (Exception e) {
            log.info(e, e);
        }
        finally {
            if (conn != null && !conn.isConnected()) {
                conn = null;
            }
        }

    }

    private synchronized ItunesConnection getItunesConnection(
            JmDNS jmdns,
            ServiceEvent event) throws IOException, NoServerPermissionException {
        ItunesConnectionFactory factory = new ItunesConnectionFactory();
        ItunesConnection conn = null;
        final ServiceInfo info = event.getInfo();

        log.info("address: " + info.getHostAddress());
        log.info("port: " + info.getPort());
        log.info(info);

        if (info.getAddress().isAnyLocalAddress()
                || info.getAddress().isLoopbackAddress()) {
            log.info("local connection");
            // return null;
        }

        try {
            log.info("connecting");
            conn = factory.produceConnectionInstance(
                    info.getHostAddress(),
                    info.getPort(),
                    event.getName());
        }
        catch (Exception e) {
            System.exit(1);
        }

        return conn;
    }
}